using System;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using ScintillaNet;
using WeifenLuo.WinFormsUI.Docking;

namespace FROG
{
    public partial class WorkSheet : DockContent, IDocumentView
    {
        public WorkSheet()
        {
            InitializeComponent();
            PopulateConnections();
            App.OpenConnections.ItemAdded += new ListChangedEventHandler<OpenConnection>(OpenConnections_Changed);
            App.OpenConnections.ItemRemoved += new ListChangedEventHandler<OpenConnection>(OpenConnections_Changed);
            sciSQL.Snippets.List = App.Config.Snippets;
        }

        #region Public properties and associated backing fields

        private OpenConnection  _connection;
        public OpenConnection Connection
        {
            get { return _connection; }
            set
            {
                if (value != _connection)
                {
                    if (_connection != null)
                    {
                        _connection.ConnectionClosed -= _connection_ConnectionClosed;
                    }
                    _connection = value;
                    if (_connection != null)
                    {
                        _connection.ConnectionClosed += _connection_ConnectionClosed;
                    }
                    SetConnectionUI();
                    UpdateTitle();
                    OnConnectionChanged();
                }
            }
        }

        public override string Text
        {
            get
            {
                if (_connection != null)
                    return string.Format(
                        "{0}{1} [{2}]",
                        this.DisplayName,
                        (_modified)?"*":"",
                        _connection.Database.Name);
                else
                    return string.Format(
                        "{0}{1}",
                        this.DisplayName,
                        (_modified) ? "*" : "");
            }
            set
            {
                base.Text = value;
                this.TabText = value;
            }
        }

        #endregion

        #region Public events and associated helpers

        public event EventHandler ConnectionChanged;

        protected void OnConnectionChanged()
        {
            if (ConnectionChanged != null)
                ConnectionChanged(this, EventArgs.Empty);
        }

        protected void OnModifiedChanged()
        {
            if (ModifiedChanged != null)
                ModifiedChanged(this, EventArgs.Empty);
        }

        protected void OnFilenameChanged()
        {
            if (FilenameChanged != null)
                FilenameChanged(this, EventArgs.Empty);
        }

        protected void OnDisplayNameChanged()
        {
            if (DisplayNameChanged != null)
                DisplayNameChanged(this, EventArgs.Empty);
        }

        #endregion

        #region App event handlers

        void OpenConnections_Changed(object sender, ListChangedEventArgs<OpenConnection> e)
        {
            PopulateConnections();
            SetConnectionUI();
        }

        void _connection_ConnectionClosed(object sender, EventArgs e)
        {
            this.Connection = null;
        }

        #endregion

        #region UI event handlers

        private void btnExecute_Click(object sender, EventArgs e)
        {
            ExecuteCurrentCommand();
        }

        private void btnExecScript_Click(object sender, EventArgs e)
        {
            ExecuteScript();
        }

        private void btnExplain_Click(object sender, EventArgs e)
        {
            ExplainCurrentCommand();
        }

        private void btnCommit_Click(object sender, EventArgs e)
        {
            if (_connection != null)
            {
                _connection.Commit();
            }
        }

        private void btnRollback_Click(object sender, EventArgs e)
        {
            if (_connection != null)
            {
                _connection.Rollback();
            }
        }

        private void WorkSheet_Load(object sender, EventArgs e)
        {
            sciSQL.ConfigurationManager.Language = "mssql";
            App.WorkSheets.Add(this);
        }

        private void WorkSheet_FormClosed(object sender, FormClosedEventArgs e)
        {
            App.OpenConnections.ItemAdded -= OpenConnections_Changed;
            App.OpenConnections.ItemRemoved -= OpenConnections_Changed;
            if (_connection != null)
                _connection.ConnectionClosed -= _connection_ConnectionClosed;
            App.WorkSheets.Remove(this);
        }

        private void sciSQL_DocumentChange(object sender, NativeScintillaEventArgs e)
        {
            Modified = sciSQL.Modified;
        }

        private void ddbConnection_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            OpenConnection cnx = e.ClickedItem.Tag as OpenConnection;
            if (cnx != null)
            {
                this.Connection = cnx;
            }
        }

        private void sciSQL_SavePointLeft(object sender, EventArgs e)
        {
            this.Modified = true;
        }

        private void sciSQL_SavePointReached(object sender, EventArgs e)
        {
            this.Modified = false;
        }

        private void sciSQL_KeyDown(object sender, KeyEventArgs e)
        {
            bool handled = true;
            switch (e.KeyCode)
            {
                case Keys.F5:
                    ExecuteScript();
                    break;
                case Keys.F6:
                    ExplainCurrentCommand();
                    break;
                case Keys.F9:
                    ExecuteCurrentCommand();
                    break;
                case Keys.Enter:
                    if (ModifierKeys == Keys.Control)
                        ExecuteCurrentCommand();
                    else
                        handled = false;
                    break;
                default:
                    handled = false;
                    break;
            }
            if (handled)
                e.Handled = true;
        }

        private void dgvResults_Scroll(object sender, ScrollEventArgs e)
        {
            if (e.ScrollOrientation == ScrollOrientation.VerticalScroll && e.NewValue > e.OldValue)
            {
                int lastDisplayedRowIndex = dgvResults.FirstDisplayedScrollingRowIndex + dgvResults.DisplayedRowCount(true) - 1;
                if (lastDisplayedRowIndex == dgvResults.RowCount - 1)
                {
                    FetchNextResults();
                }
            }
        }

        private void dgvResults_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            if (e.Value != null && e.Value != DBNull.Value)
            {
                object tag = dgvResults.Columns[e.ColumnIndex].Tag;
                string dataTypeName = "";
                if (tag != null)
                    dataTypeName = tag.ToString();
                if (Connection.IsBlobType(dataTypeName))
                {
                    e.Value = "(BLOB)";
                }
                else if (string.IsNullOrEmpty(dataTypeName))
                {
                    e.Value = "(Unknown type)";
                }
            }
        }

        #endregion

        #region IDocumentView Members

        public void Save(string filename)
        {
            using (StreamWriter wr = new StreamWriter(filename))
            {
                wr.Write(sciSQL.Text);
                wr.Close();
                Filename = filename;
                Modified = false;
                _isNew = false;
            }
        }

        public void Open(string filename)
        {
            using (StreamReader rd = new StreamReader(filename))
            {
                sciSQL.Text = rd.ReadToEnd();
                rd.Close();
                Filename = filename;
                Modified = false;
                _isNew = false;
            }
        }

        private bool _modified = false;

        public bool Modified
        {
            get { return _modified; }
            protected set
            {
                if (value != _modified)
                {
                    _modified = value;
                    OnModifiedChanged();
                    UpdateTitle();
                }
            }
        }

        private string _filename = null;

        public string Filename
        {
            get { return _filename; }
            protected set
            {
                if (value != _filename)
                {
                    _filename = value;
                    OnFilenameChanged();
                    OnDisplayNameChanged();
                    UpdateTitle();
                }
            }
        }

        public string DisplayName
        {
            get
            {
                if (string.IsNullOrEmpty(_filename))
                {
                    return this.Name;
                }
                else
                {
                    FileInfo fi = new FileInfo(_filename);
                    return fi.Name;
                }
            }
        }

        private bool _isNew = true;
        public bool IsNew
        {
            get { return _isNew; }
        }

        public event EventHandler ModifiedChanged;
        public event EventHandler FilenameChanged;
        public event EventHandler DisplayNameChanged;

        #endregion

        private void PopulateConnections()
        {
            ddbConnection.DropDownItems.Clear();
            foreach (OpenConnection cnx in App.OpenConnections)
            {
                ToolStripMenuItem mnu = new ToolStripMenuItem(cnx.Database.Name);
                mnu.Image = Properties.Resources.database;
                mnu.Tag = cnx;
                ddbConnection.DropDownItems.Add(mnu);
            }
        }

        private void SetConnectionUI()
        {
            foreach (ToolStripItem item in ddbConnection.DropDownItems)
            {
                ToolStripMenuItem mnu = item as ToolStripMenuItem;
                if (mnu != null)
                {
                    if (mnu.Tag == _connection)
                    {
                        mnu.Checked = true;
                        ddbConnection.Text = mnu.Text;
                        ddbConnection.Image = Properties.Resources.database;
                    }
                    else
                    {
                        mnu.Checked = false;
                    }
                }
            }
            
            if (_connection == null)
            {
                SelectNotConnected();
                lblAutoCommit.Text = "(not connected)";
                lblAutoCommit.Image = Properties.Resources.light_gray;
            }
            else
            {
                if (_connection.AutoCommit)
                {
                    lblAutoCommit.Text = "Autocommit on";
                    lblAutoCommit.Image = Properties.Resources.light_green;
                }
                else
                {
                    lblAutoCommit.Text = "Autocommit off";
                    lblAutoCommit.Image = Properties.Resources.light_red;
                }
            }
        }

        private void SelectNotConnected()
        {
            ddbConnection.Text = "(not connected)";
            ddbConnection.Image = Properties.Resources.database_error;
        }

        private void UpdateTitle()
        {
            this.Text = this.Text;
            if (this.DockHandler.Pane != null)
                this.DockHandler.Pane.Refresh();
        }

        private void AppendError(string text)
        {
            rtbOutput.Select(rtbOutput.TextLength, 0);
            rtbOutput.SelectionColor = Color.Red;
            rtbOutput.SelectedText = text;
            rtbOutput.ScrollToCaret();
        }

        private void AppendText(string text)
        {
            rtbOutput.Select(rtbOutput.TextLength, 0);
            rtbOutput.SelectionColor = Color.Black;
            rtbOutput.SelectedText = text;
            rtbOutput.ScrollToCaret();
        }
    }
}
